iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 23
2

什麼是異步呢?

一般我們執行程式碼都是直接回傳值,這稱為同步;異步跟這行為相反,我們執行程式碼時,也許因為該段程式碼需要花費時間去執行、也或許需要等待資料,這個時候,我們真實需要的資料、結果沒有辦法在執行程式碼之後直接取得,此時,我們就必須要使用異步的方式來執行程式。

在 Dart 中,異步工作分為兩種:FutureStream

Future 是用在結果會在未來完成的情況,而 Stream 是用在資料流的情況。

針對異步的工作 Dart 提供了關鍵字 async 以及 await 來處理它。

Future

在 Dart/Flutter 中,有許多 API 都是以 Future 來處理資料,例如 Http 請求 (Http request)、SharedPreference ...

Future 類別中,包含了幾個常用的靜態函數,方便我們直接建立一個 Future

Future.value

Future<int> futureWait(){
	return Future.value(10);
}

void main(){
	futureWait().then((value)=>print(value));
}
//10
  • 將欲回傳的值填在 Future.value 中,該數值就會以 Future 的形式回傳。

將普通的數值轉成 Future 有什麼好處呢?

Future 類別包含了幾個函數,我們可以直接串接在 Future 之後。

如上方範例的 then

  • then(value) :在 Future 的數值回傳之後,就可以在 then 裡面使用這個數值,如 print(value)
  • whenComplete() :當 Future 完成之後,最後就會呼叫到 whenComplete
void main(){
	futureWait().then((value) => print(value))
.whenComplete(()=> print('done'));
}
//10
//done

Future.delayed

在測試 Future 時, Future.delayed 是最方便的一個函數。

在 Future.delayed 中帶入一個 Duration ,時間到了之後就會執行 Future 內的函數。

Future<String> futureDelayed(){
	return Future.delayed(Duration(seconds: 1),
 () => 'Delay 1 second');
}

void main(){
	futureDelayed().then((value) => print(value));
}
//Delay 1 second
  • 如上面的範例,在執行 Future.delayed 函數之後,在一秒之後就回傳值了。我們同樣可以利用 then 將數值列印出來。

Future.error

除了正確的資料外,當錯誤發生時,我們也可以用 Future 將錯誤捕捉起來。 Future.error 可以發出一個 Future 的 錯誤。

Future<String> futureError(){
	return Future.error('error message');
}

void main(){
	futureError().catchError((error) => print(error));
}
//error message
  • 這邊是利用 Future類別的 catchError 函數來捕捉。

Async/Await 關鍵字

前面提到,Dart 是用 async 以及 await 關鍵字來處理異步。

那麼要如何使用呢?

呼叫異步函數的時候,每一個異步函數回傳的時間都不一樣,如果我們需要等待異步函數的回傳值才繼續,我們就可以使用 async 以及 await 關鍵字。

例如:

假設有兩個 Future 函數,一個需要花費一秒回傳10,另一個直接回傳 true。


void testFutureMethod(){
		futureMethod1().then((value)=> print(value));
		futureMethod2().then((value) => print(value));
}

Future<int> futureMethod1(){
	return Future.delayed(Duration(seconds: 1), ()=>10);
}

Future<bool> futureMethod2(){
	return Future.value(true);
}
  • 我們嘗試呼叫看看
void main(){
	testFutureMethod();
}
//true
...1 second...
//10

結果會先傳出方法2的回傳值 true,接者才是方法1 的 10。

因為異步沒有順序,會根據完成的順序來回傳。

使用 async 以及 await

將 testFutureMethod 函數加上 async 以及 await 關鍵字。

async :用來表示該函數是異步函數。

await :用來表示要等待異步函數完成。

void testFutureMethod() async{
		await futureMethod1().then((value)=> print(value));
		await futureMethod2().then((value) => print(value));
}
void main(){
	testFutureMethod();
}
...1 second...
//10
//true
  • 結果變成經過1 秒之後,才顯示第一個方法的回傳值,接者才是第二個方法的回傳值。
  • 異步函數的順序因為 async 以及 await 關鍵字變得有順序了。

小結

Future 表示會回傳是的值可能會經過一些運算時間,可能會需要多一些時間等待。有時候不見得是本機端很忙需要等待,網路的請求常常也會需要一些時間,所以在網路的應用上很常見到 Future 。

Future 的結果會有兩種,一種是正常的結果,另一種是錯誤的結果。我們可以用 then 來處理 Future 函數的正常結果,用 catchError 處理異常的結果。

異步,表示完成的時間不一樣,如果需要在同一個函數中進行有順序的異步函數呼叫。可以使用async 以及 await 關鍵字。

利用 async 將函數宣告成異步函數。用 await 決定要等待哪一個函數。

在 async 函數中,可以使用多個 await。使用 await 一定要在 async 函數中。


上一篇
Dart 22:將函數定義成型別吧。 (Typedef)
下一篇
Day 24:異步處理 Part2-Stream
系列文
Dart 語言 - 開啟 Flutter 的鑰匙30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言